/*******************************************************************************
* @brief  can quene
* can 队列
* 该队列管理模块，不支持多任务处理，需要多任务管理时，须使用互斥量保护
* 该模块分为缓存管理和命令管理两部分，命令管理使用缓存管理接口完成底层操作
* simp_canfd_cmd_poll_ack 不能和其他rt类API混合使用。
* 除上一条之外，缓存管理，命令管理，命令执行可以混合使用，不受限制。
* 硬件发送缓冲区须配置为先进先出模式
* *****************************************************************************
* 以下内容为建议规则而非强制
* ID分为两部分：
* ID设备识别区    - 用于CAN过滤器过滤报文,    STD[10:7] <15 节点>,   EXT[29:16] 
* 功能码/数据地址 - 指示报文功能 / 数据地址,  STD[7:0]  <128>    ,   EXT[15:0]
*******************************************************************************/

#ifndef __CANFDQUENE_H
#define	__CANFDQUENE_H

#include <stdint.h>
#include "mytype.h"
#include "dataproc.h"
#include "can_quene.h"

#ifdef	__cplusplus
extern "C" {
#endif
	
	#define CAN_FD_DAT_SIZE					64
	
	/*******************************************************************************
	* @brief  can frame define
	*******************************************************************************/
	typedef struct
	{
		uint32_t id;
		uint8_t id_mode;
		uint8_t remot;
		uint8_t len;
		dword_tt fd_dat[16];
	} simp_canfd_frame_type;
	
	typedef struct
	{
		uint32_t id;     //0xFFFFFFFF代表空闲
		uint8_t id_mode;
		uint8_t remot;
		uint16_t len;
		void *dat;
	} simp_canfd_cmd_type;
	
	/*******************************************************************************
	* @brief  can control define
	*******************************************************************************/
	struct simp_canfd_frame_ctr_str
	{
		volatile uint16_t tx_site_fill; //待填充位置
		uint16_t tx_site_send;          //待发送位置
		
		volatile uint16_t tx_rt_site_fill; //待填充位置
		uint16_t tx_rt_site_send;          //待发送位置
		
		volatile uint16_t rx_site_rcv;  //待接收位置
		uint16_t rx_site_read;          //待读取位置
				
		volatile enum simp_can_snd_st_type tx_st;         //发送状态
		
		//计时统计
		uint16_t tx_idle_time_cnt;		//发送器空闲计时
		uint16_t tx_frame_time_cnt;		//帧计时
		uint16_t tx_act_time_cnt;		//发送器活动计时
		uint16_t rx_idle_time_cnt;		//接收器空闲计时
		uint16_t hal_idle_time_cnt;     //tx, tx均空闲计时
		
		//统计
		uint32_t tx_cnt;
		uint32_t rx_cnt;
		
		//以下仅初始配置
		uint16_t tx_buff_amount;
		uint16_t tx_rt_buff_amount;
		uint16_t rx_buff_amount;
		simp_canfd_frame_type *rx_frame;
		simp_canfd_frame_type *tx_frame;
		simp_canfd_frame_type *tx_rt_frame;
		void(*tx_send)(simp_canfd_frame_type *);
		void(*rx_handle)(simp_canfd_frame_type *);
		uint8_t (*is_tx_hal_empty)(void);
		uint8_t (*is_tx_hal_full)(void);
		
		//cmd manager, 不使用 cmd api时无需初始化
		uint16_t cmd_exe_time_interval;	//命令执行时间间隔
		uint16_t os_event_req;
		uint8_t cmd_stc_site_exe;	//待执行位置
		uint8_t cmd_stc_amount;
		uint8_t cmd_sync_site_exe;	//待执行位置
		uint8_t cmd_sync_site_fill;	//待填充位置
		uint8_t cmd_sync_amount;
		uint8_t cmd_exe_mode;       //0静态，x动态
		uint8_t ack_master;
		uint8_t ack_len_req;
		uint8_t ack_rcv_cnt;
		uint8_t ack_err_cnt;
		uint32_t ack_id_mask;      //从模式应答地址掩模
		uint32_t ack_id_comp;      //从模式应答地址匹配
		void (*cmd_handle_callback)(uint8_t err_st, struct simp_canfd_frame_ctr_str *quene);
		void (*os_event_send)(uint16_t event);
		simp_canfd_cmd_type *stc_cmd_buff;
		simp_canfd_cmd_type *sync_cmd_buff;
		simp_canfd_cmd_type cmd_exe_now;
	};

	typedef struct simp_canfd_frame_ctr_str simp_canfd_frame_ctr_type;
	
	////////////////////////////////////////////////////////////////////////////
	//////////////////////////////  BUFFER API  ////////////////////////////////
	////////////////////////////////////////////////////////////////////////////
	// 缓存扫描处理
	void simp_canfd_poll(simp_canfd_frame_ctr_type * ctr);
	
	// 缓存发送
	enum simp_can_snd_st_type simp_canfd_transmit(simp_canfd_frame_ctr_type * ctr);
	
	// 发送报文到普通缓存
	uint8_t simp_canfd_send(simp_canfd_frame_ctr_type * ctr, simp_canfd_frame_type *frame);
	
	// 发送报文到高优先级缓存
	uint8_t simp_canfd_rt_send(simp_canfd_frame_ctr_type * ctr, simp_canfd_frame_type *frame);
	
	// 接收报文到接收缓存
	uint8_t simp_canfd_receive(simp_canfd_frame_ctr_type * ctr, simp_canfd_frame_type *frame);
	
	// 普通发送缓存使用数量
	uint16_t simp_canfd_tx_buff_used_amount(simp_canfd_frame_ctr_type * ctr);

	// 普通发送缓存剩余数量
	uint16_t simp_canfd_tx_buff_remain_amount(simp_canfd_frame_ctr_type * ctr);
	
	// 高优先级发送缓存使用数量
	uint16_t simp_canfd_tx_rt_buff_used_amount(simp_canfd_frame_ctr_type * ctr);
	
	// 高优先级发送缓存剩余数量
	uint16_t simp_canfd_tx_rt_buff_remain_amount(simp_canfd_frame_ctr_type * ctr);
	
	// 计时处理
	void simp_canfd_time_run(simp_canfd_frame_ctr_type * ctr);
	
	////////////////////////////////////////////////////////////////////////////
	////////////////////////////////  CMD API  /////////////////////////////////
	////////////////////////////////////////////////////////////////////////////
	// 命令初始化
	void simp_canfd_cmd_init(
		simp_canfd_frame_ctr_type * quene,
		simp_canfd_cmd_type *stc_cmd_buff,
		uint8_t stc_cmd_amount,
		simp_canfd_cmd_type *sync_cmd_buff,
		uint8_t sync_cmd_amount);
	
	// 静态命令请求
	uint8_t simp_canfd_stc_cmd_req(
		simp_canfd_frame_ctr_type * quene,
		uint8_t cmd_site,
		simp_canfd_cmd_type *cmd);
	
	// 静态命令删除
	uint8_t simp_canfd_stc_cmd_del(
		simp_canfd_frame_ctr_type * quene,
		uint8_t cmd_site);
	
	// 动态命令请求
	uint8_t simp_canfd_sync_cmd_req(
		simp_canfd_frame_ctr_type * quene,
		simp_canfd_cmd_type *cmd);
	
	// 动态命令使用量
	uint16_t simp_canfd_sync_cmd_used_amount(simp_canfd_frame_ctr_type * ctr);
	
	// 动态命令剩余量
	uint16_t simp_canfd_sync_cmd_remain_amount(simp_canfd_frame_ctr_type * ctr);
	
	// 命令执行,数据分拆方式为, 帧长度64*n+b， id自增(id+n)
	// 适用于地址映射法数据传输
	// cmd_mode： 0-指示普通发送缓存， 1-指示rt发送缓存
	uint8_t simp_canfd_cmd_exe(
		simp_canfd_frame_ctr_type * quene, 
		simp_canfd_cmd_type *cmd,
		uint8_t cmd_mode);
	
	// 命令执行,数据分拆方式为, 帧长度62*n+b， id保持不变
	// dat[1:0]指示偏移量, dat[7:2]为传送数据
	// 适用于设备地址不变，数据子地址映射
	// cmd_mode： 0-指示普通发送缓存， 1-指示rt发送缓存 
	uint8_t simp_canfd_ext_cmd_exe(
		simp_canfd_frame_ctr_type * quene, 
		simp_canfd_cmd_type *cmd,
		uint16_t sub_addr,
		uint8_t cmd_mode);
	
	// 命令执行,数据分拆方式为, 帧长度64*n+b， id保持不变
	// 适用于连续包传输，软件应检测数据完整性
	// cmd_mode： 0-指示普通发送缓存， 1-指示rt发送缓存
	uint8_t simp_canfd_split_cmd_exe(
		simp_canfd_frame_ctr_type * quene, 
		simp_canfd_cmd_type *cmd,
		uint8_t cmd_mode);
	
	// 命令扫描， 发送命名使用 simp_canfd_cmd_exe, 
	// 可以和任意指令混用
	// 应保证至少一条静态或动态指令有效，扫描静态和动态命令缓存发送命令
	void simp_canfd_cmd_poll_mute(simp_canfd_frame_ctr_type * quene);
	
	//----------------------------------------------------------------------
	// 命令扫描， 发送命名使用 simp_canfd_ack_cmd_exe
	//----------------------------------------------------------------------
	// 配置ack_master=1 模式的为主机，等待返回ACK，否则为从机，返回ACK
	// 主机-动态命令等待并检测 ACK
	// 主机-静态命令同 mute，无需ACK
	// 从机-动态静态命令均同 mute，无需ACK
	//----------------------------------------------------------------------
	// 命令请求的ID.b0应保持为0。
	// 数据分包ID自增2，quene->rx_handle确定地址应&~1UL, b[0]指示帧含ACK
	// 发送打包时，主机动态命令物理层ID.b0为1，其余状态命令ID.b0为0
	//----------------------------------------------------------------------
	// 不能 和 RT操作的指令混用， 但其他指令可用，但应保证ID的bit[0]为0
	// 不能 和 simp_canfd_cmd_exe 混用，因为其内部有地址自增1操作
	//----------------------------------------------------------------------
	// 单个动态命令的数据长度不能大于256can帧，静态命令只受发送缓存尺寸限制
	// 动态命令错误重发次数3（含首次），超时间隔为发送器空闲后50ms
	// 动态命令格式为   远程帧(LEN=0)+数据帧n+远程帧(LEN=1)
	// 反馈机制内部处理，app无需关心， 注意ID不重复即可
	//----------------------------------------------------------------------
	// 滤波器设置应保证主模式的动态命令仅有一个器件响应
	// 应保证至少一条静态或动态指令有效
	//----------------------------------------------------------------------
	void simp_canfd_cmd_poll_ack(simp_canfd_frame_ctr_type * quene);
	void simp_canfd_cmd_slave_ack_id(
		simp_canfd_frame_ctr_type * quene,
		uint32_t mask, 
		uint32_t comp);
	
#ifdef	__cplusplus
}
#endif

#endif	/* __CANQUENE_H */
